package com.sdp.right.db.sys_dict.service.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sdp.core.bizc.drop.IFilterDropManager;
import com.sdp.core.bizc.exception.ApplicationException;
import com.sdp.core.bizc.exception.ExceptionMessage;
import com.sdp.core.bizc.listener.CacheListener;
import com.sdp.core.bizc.redis.RedisUtil;
import com.sdp.core.bizc.utils.ApplicationContextUtils;
import com.sdp.core.bizc.vo.CacheInfo;
import com.sdp.right.db.sys_dict.mapper.SysDictMapper;
import com.sdp.right.db.sys_dict.service.ISysDictService;
import com.sdp.right.db.sys_dict_item.service.ISysDictItemService;
import com.sdp.right.entity.SysDict;
import com.sdp.right.entity.SysDictItem;
import com.sdp.right.service.RemoveSystemService;
import com.sdp.right.utils.RightConstants;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zsp
 * @since 2023-10-11
 */
@Service
@DS(value="right")
public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> implements ISysDictService,RemoveSystemService {
	
	@Autowired
	private RedissonClient redissonClient;
	
	@Autowired
	private RedisUtil redisUtil;
	
	@Autowired
	private ISysDictItemService iSysDictItemService;
	
	@Autowired
	private CacheListener cacheListener;
	


	@Override
	@SuppressWarnings("unchecked")
	public List<Object> getDictInfo(String dictCode, String... arg) {
		List<Object> returnList = new ArrayList<>();
		RLock lock = redissonClient.getLock(RightConstants.获取数据字典时REDIS锁名.getCode());
		SysDict sysDict = null;
		try {
			if (lock.tryLock(5, TimeUnit.SECONDS)) {
				try {
					//先从缓存中取值
					sysDict = redisUtil.getMap(SysDict.class, dictCode);
					if(sysDict==null) {
						//如果缓存不存在，从数据库中取值
						sysDict = querySysDict(dictCode,RightConstants.是.getCode());
						if(sysDict==null) {
							return returnList;
						}
						redisUtil.setMap(SysDict.class, dictCode, sysDict);
						redisUtil.setMap(SysDictItem.class,dictCode,iSysDictItemService.querySysDictItem(dictCode));
					}
					
					if(RightConstants.自定义缓存字典.getCode().equals(sysDict.getDictType())) {
						if(!StringUtils.isEmpty(sysDict.getCacheKey())) {
							IFilterDropManager dropManager = (IFilterDropManager)ApplicationContextUtils.getBean(Class.forName(sysDict.getCacheKey()));
							returnList = (List<Object>) dropManager.getDropData(sysDict.getDictParam());
							//数据转换
							returnList = dictReplage(sysDict, returnList);
						}
						
					}else if(RightConstants.缓存字典.getCode().equals(sysDict.getDictType())) {
						returnList = this.cacheDictInfo(sysDict.getCacheKey(), arg);	
						//这里进行替换
						returnList = dictReplage(sysDict, (List<Object>)  returnList);
					}else {
						returnList = (List<Object>) redisUtil.getMap(SysDictItem.class, dictCode);
					}
				} catch (Exception e) {
					throw new ApplicationException(ExceptionMessage.getExceptionMessage(e));
				}finally {
					lock.unlock(); 
				}
			}
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}
		
		return returnList;
	}

	
	@Override
	public List<Object> getCacheDictInfo(String cacheKey, String... arg) {
		List<Object> returnList = new ArrayList<>();
		RLock lock = redissonClient.getLock(RightConstants.获取数据字典时REDIS锁名.getCode());
		try {
			if (lock.tryLock(5, TimeUnit.SECONDS)) {
				try {
					returnList = this.cacheDictInfo(cacheKey, arg);
				} catch (Exception e) {
					throw new ApplicationException(ExceptionMessage.getExceptionMessage(e));
				}finally {
					lock.unlock(); 
				}
			}
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}
		
		return returnList;
	}
	
	@SuppressWarnings("unchecked")
	private List<Object> cacheDictInfo(String cacheKey, String... arg) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Object cacheObj = null;
		String fieldKey = null;
		if(!StringUtils.isEmpty(arg) && arg.length > 0) {
			StringBuffer sbf = new StringBuffer("");
			for (int i = 0, count = arg.length; i < count; i++){
				if(i<arg.length-1) {
					sbf.append(arg[i]).append("#");
				}else {
					sbf.append(arg[i]);
				}
			}
			
			fieldKey = sbf.toString();
		}
		
		if(redisUtil.hasKey(cacheKey)) {
			if(StringUtils.isEmpty(fieldKey)) {
				cacheObj = redisUtil.get(cacheKey);
			}else {
				cacheObj = redisUtil.getMap(cacheKey, fieldKey);
			}
		}
		
		if(cacheObj!=null) {
			return (List<Object>)  cacheObj;
		}
		
		CacheInfo cacheInfo = cacheListener.getCacheMap().get(cacheKey);
		if(cacheInfo==null) {
			return (List<Object>)  cacheObj;
		}
		
		Type[] types = cacheInfo.getMethod().getGenericParameterTypes();
		if(types.length==0) {
			cacheObj = cacheInfo.getMethod().invoke(cacheInfo.getBean());
		}else {
			Object[] argObj = new Object[types.length];
			for (int i = 0, count = types.length; i < count; i++){
				argObj[i] = arg[i];
			}
			cacheObj =  cacheInfo.getMethod().invoke(cacheInfo.getBean(),argObj);
		}
		if(StringUtils.isEmpty(fieldKey)) {
			redisUtil.set(cacheKey, cacheObj);
		}else {
			redisUtil.setMap(cacheKey, fieldKey, cacheObj);
		}
		return (List<Object>) cacheObj;
	}
	
	private List<Object> dictReplage(SysDict sysDict,List<Object> returnList) {
		List<Object> newReturnList = new ArrayList<>();
		if(sysDict!=null && !StringUtils.isEmpty(sysDict.getReplaceText()) && !StringUtils.isEmpty(sysDict.getReplaceValue()) ) {
			JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
			String replaceText = sysDict.getReplaceText();
			String replaceValue = sysDict.getReplaceValue();
			String replaceFilter = sysDict.getReplaceFilter();
			JSONObject record = null;
			
			for(int i=0;i<returnList.size();i++) {
				record = JSON.parseObject(JSON.toJSONStringWithDateFormat(returnList.get(i), "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteMapNullValue,SerializerFeature.WriteDateUseDateFormat));
				record.put("itemText", record.getString(replaceText));
				record.put("itemValue", record.getString(replaceValue));
				if(!StringUtils.isEmpty(replaceFilter)) {
					record.put("itemFilter", record.getString(replaceFilter));
				}
				newReturnList.add(record);
			}
			return newReturnList;
		}else {
			return returnList;
		}
	}
	@Override
	public SysDict querySysDict(String dictCode) {
		LambdaQueryWrapper<SysDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(SysDict::getDictCode, dictCode);
		return getOne(lambdaQueryWrapper,false);
	}

	@Override
	public SysDict querySysDict(String dictCode, String isUse) {
		LambdaQueryWrapper<SysDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(SysDict::getDictCode, dictCode);
		lambdaQueryWrapper.eq(SysDict::getDictUse, isUse);
		return getOne(lambdaQueryWrapper,false);
	}

	@Override
	public List<SysDict> queryAllUseSysDict() {
		LambdaQueryWrapper<SysDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(SysDict::getDictUse, RightConstants.是.getCode());
		lambdaQueryWrapper.orderByAsc(SysDict::getDictType);
		return list(lambdaQueryWrapper);
	}


	@Override
	public void removeBySystemNo(String systemNo) {
		LambdaQueryWrapper<SysDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(SysDict::getSystemNo, systemNo);
		List<SysDict> list = list(lambdaQueryWrapper);
		List<String> dictCodes = new ArrayList<>();
		if(list!=null && list.size()>0) {
			for(SysDict dict : list) {
				dictCodes.add(dict.getDictCode());
			}
			
			LambdaQueryWrapper<SysDictItem> queryWrapper = new LambdaQueryWrapper<>();
			queryWrapper.in(SysDictItem::getDictCode, dictCodes);
			iSysDictItemService.remove(queryWrapper);
			
			remove(lambdaQueryWrapper);
		}
		
	}

}
